package com.own.business.login.controller;

import com.own.aop.login.LoginIgnore;
import com.own.business.login.controller.vo.LastLoginTimeVo;
import com.own.business.login.core.core.UserSpringHook;
import com.own.business.login.core.service.AfterDetailUserInfoService;
import com.own.business.login.core.service.AutoLoginService;
import com.own.business.system.account.common.em.AccountType;
import com.own.component.common.base.controller.BaseController;
import com.own.component.common.login.core.UserStatusSpringHook;
import com.own.component.common.login.util.SessionUserUtil;
import com.own.component.common.model.R;
import com.own.component.common.model.ResultModel;
import com.own.component.common.util.list.ListUtil;
import com.own.component.log.login.core.BaseLastLoginTimeMethod;
import com.own.component.log.login.util.LogLoginUtil;
import com.own.component.log.operation.aop.LogOperationAop;
import com.own.component.store.core.confirm.aop.ConfirmAop;
import com.own.component.store.core.util.base.RsaKeyUtil;
import com.own.component.token.base.StoreTokenManager;
import com.own.constant.ConstantApiPrefix;
import com.own.constant.ConstantBeanSuffix;
import com.own.constant.ConstantEnvironmentType;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Profile;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.Map;

/**
 * LoginBaseController
 *
 * @author chenxueli
 * @date 2023-10-12 09:44:00
 */
@Slf4j
@Tag(name = "登录基础" + ConstantBeanSuffix.CONTROLLER)
@RestController
@RequestMapping(ConstantApiPrefix.BASE_API_V1_PREFIX + "login")
public class LoginBaseController extends BaseController {

    @Resource
    private AfterDetailUserInfoService afterDetailUserInfoService;
    @Resource
    private AutoLoginService autoLoginService;

    @Resource
    private BaseLastLoginTimeMethod baseLastLoginTimeMethod;

    @Resource
    private UserSpringHook userSpringHook;
    @Resource
    private UserStatusSpringHook userStatusSpringHook;

    @Resource
    private StoreTokenManager storeTokenManager;

    @Resource
    private RsaKeyUtil rsaKeyUtil;

    @Resource
    private LogLoginUtil logLoginUtil;

    @LoginIgnore
    @LogOperationAop
    @Operation(summary = "验证是否登录")
    @GetMapping("/check")
    public ResultModel<Boolean> check() {
        var loginUser = SessionUserUtil.getLoginUser(false);
        var flag = loginUser.isLogin();
        if (flag) {
            logLoginUtil.success(loginUser, AccountType.Type.AWAKEN);
        }
        return R.success(flag);
    }

    @LoginIgnore
    @LogOperationAop
    @ConfirmAop(message = "确定退出登录？退出之后所有的信息都不会在客户端保存")
    @Operation(summary = "退出登录")
    @DeleteMapping("/")
    public ResultModel<Boolean> loginOut() {
        var loginUser = SessionUserUtil.getLoginUser(false);
        if (loginUser.isLogin()) {
            logLoginUtil.success(loginUser, AccountType.Type.LOGIN_OUT);
        }
        // 清除当前登录用户的相关信息
        userStatusSpringHook.clear(loginUser);
        return R.success(true);
    }

    @LogOperationAop
    @Operation(summary = "获取登录的用户信息")
    @GetMapping("/")
    public ResultModel<Map<String, Object>> detail() {
        var loginUser = SessionUserUtil.getLoginUser();
        // 通过钩子方法获取用户信息
        var map = userSpringHook.detail(loginUser);
        // 自定义处理登录用户信息
        afterDetailUserInfoService.afterDetailUserInfoMethod(loginUser.userId(), map);
        return R.success(map);
    }

    @LogOperationAop
    @Operation(summary = "获取当前用户最新登录的时间")
    @GetMapping("/last/login/time")
    public ResultModel<LastLoginTimeVo> lastLoginTime() {
        var loginUser = SessionUserUtil.getLoginUser();
        var entity = baseLastLoginTimeMethod.lastLoginTime(loginUser.userId());
        var vo = new LastLoginTimeVo(entity.getLoginTime());
        return R.success(vo);
    }

    @LoginIgnore
    @LogOperationAop
    @Operation(summary = "获取登录公钥")
    @GetMapping("/key/{sign}")
    public ResultModel<String> getPublicKey(
            @Parameter(description = "加密标识") @PathVariable String sign
    ) {
        var key = rsaKeyUtil.build(sign);
        return R.success(key.getPublicKey());
    }

    @LoginIgnore
    @LogOperationAop
    @Profile({ConstantEnvironmentType.DEV, ConstantEnvironmentType.LOCALHOST, ConstantEnvironmentType.TEST})
    @Operation(summary = "加密内容")
    @GetMapping("/encrypt/{sign}")
    public ResultModel<String> getPublicKey(
            @Parameter(description = "加密标识") @PathVariable String sign,
            @Parameter(description = "待加密的内容") @RequestParam String content
    ) {
        var text = rsaKeyUtil.encrypt(sign, content);
        return R.success(text);
    }

    @LoginIgnore
    @LogOperationAop(defaultClient = "old")
    @Operation(summary = "根据用户id清除token")
    @PostMapping("/clear/token/by/user/id")
    public ResultModel<Boolean> clearTokenByUserId(
            @Parameter(description = "用户id") @RequestParam(required = false) Long userId,
            @Parameter(description = "客户端id，多个用英文逗号分隔") @RequestParam(required = false) String client
    ) {
        if (userId == null) {
            return R.success(false);
        }
        if (StringUtils.isBlank(client)) {
            // 清除当前登录用户的相关信息
            storeTokenManager.deleteAllByUserId(userId);
            // 清除对应的自动登录信息
            autoLoginService.deleteByUserId(userId);
        } else {
            ListUtil.Spilt.to(client, ",").forEach(item -> {
                storeTokenManager.deleteByUserId(userId, item);
                autoLoginService.deleteByUserId(userId, item);
            });
        }
        return R.success(true);
    }

}
